/*LICENSE_BEGIN
 * ******************************************************************
 * Copyright 2006 by the Dainamite Robocup-Team at the
 * DAI-Labor, TU-Berlin (www.dai-labor.de)
 * 
 * Members of Dainamite are:
 * Holger Endert
 * Robert Wetzker
 * Thomas Karbe
 * Axel Heßler
 * Philippe Bütter
 * Felix Brossmann
 * 
 * Licensed under the GNU GPL (General Public License) Free Software 
 * License, Version 2. You may use this file only in compliance with 
 * the License. You may obtain a copy of the License at:
 * 
 * http://www.fsf.org/licensing/licenses/gpl.txt
 * ******************************************************************
LICENSE_END*/
package robocup.component.worldobjects;

import static java.lang.Math.PI;
import static java.lang.Math.abs;
import static java.lang.Math.asin;
import static java.lang.Math.max;
import static java.lang.Math.min;
import static java.lang.Math.round;
import static robocup.component.geometry.Vektor.XY;
import static robocup.component.geometry.Vektor.normalize;
import static robocup.component.situations.GoalkeeperSituation.getTurnArg;
import static robocup.component.situations.GoalkeeperSituation.getTurnFromArg;

import java.util.LinkedList;

import robocup.component.PConf;
import robocup.component.SConf;
import robocup.component.actionfactories.BasicActionFactory;
import robocup.component.actions.Action;
import robocup.component.actions.DashAction;
import robocup.component.actions.TurnAction;
import robocup.component.geometry.Circle;
import robocup.component.geometry.Vektor;
import robocup.component.worldobjects.Player.RELATIVE;

/**
 * This class represents the area in that the ball could be catched by the
 * goalie in a given number of cycles
 */
public class ReachableArea {

	private static DashAction DASH_100 = new DashAction(100);

	private int cycles;

	private int reactCycles;

	private double posX;

	private double posY;

	private double bodyDir;

	private double turn1;

	private double turn2;

	private double turn3;

	private double dash0;

	private double dash1;

	private double dash2;

	private double dash3;

	private double dash4;

	private Vektor pos = new Vektor(0, 0);

	private double reachDist;

	private boolean foundValue = false;

	private Player p;

	private Player dummyPlayer;

	private Vektor dummyVektor = new Vektor();

	private Line dummyLine = new Line(new Vektor(Vektor.XY, 0, 1), new Vektor(
			Vektor.XY, 0, 0));

	private Circle dummyCircle = new Circle(new Vektor(), 1);

	/**
	 * An object, that can calculate, if certain positions are reachable in a
	 * given amount of time for a given player.
	 * 
	 * @param _cycles
	 *            number of cycles to reach the point
	 * @param _reactCycles
	 *            number of cycles until movement begins
	 * @param _p
	 *            the player who wants to reach something
	 * @param _reachDist
	 *            distance in that the position can be reached / kicked directly
	 */
	public ReachableArea(int _cycles, int _reactCycles, Player _p,
			double _reachDist) {
		this.dummyPlayer = this.p.cloned();
		this.dummyPlayer.extrapolate(_cycles,
				this.dummyPlayer.getPConf().PLAYER_DECAY);
		this.cycles = _cycles;
		this.reactCycles = _reactCycles;
		this.posX = this.dummyPlayer.getPosition().x;
		this.posY = this.dummyPlayer.getPosition().y;
		this.bodyDir = this.dummyPlayer.getBodyDir();
		this.turn1 = getTurnFromArg(180, _p);
		this.dummyPlayer.copy(_p);
		this.dummyPlayer.extrapolate(1,
				this.dummyPlayer.getPConf().PLAYER_DECAY);
		this.turn2 = getTurnFromArg(180, this.dummyPlayer) + this.turn1;
		this.dummyPlayer.extrapolate(1,
				this.dummyPlayer.getPConf().PLAYER_DECAY);
		this.turn3 = getTurnFromArg(180, this.dummyPlayer) + this.turn2;
		if (this.turn1 > 180) {
			this.turn1 = 181;
		}
		if (this.turn2 > 180) {
			this.turn2 = 181;
		}
		if (this.turn3 > 180) {
			this.turn3 = 181;
		}
		this.dummyPlayer.setSpeed(new Vektor(0, 0));
		this.dummyPlayer.setPosition(new Vektor(0, 0));
		this.dummyPlayer.setBodyDir(0);
		this.dash0 = 0;
		this.dash1 = 0;
		this.dash2 = 0;
		this.dash3 = 0;
		this.dash4 = 0;
		for (int i = this.cycles - 1 - this.reactCycles; i >= 0; i--) {
			this.dummyPlayer.predictThisAfterAction(DASH_100);
			if (i == 4) {
				this.dash4 = this.dummyPlayer.getPosition().y;
			}
			if (i == 3) {
				this.dash3 = this.dummyPlayer.getPosition().y;
			}
			if (i == 2) {
				this.dash2 = this.dummyPlayer.getPosition().y;
			}
			if (i == 1) {
				this.dash1 = this.dummyPlayer.getPosition().y;
			}
			if (i == 0) {
				this.dash0 = this.dummyPlayer.getPosition().y;
			}
		}
		this.reachDist = _reachDist;
		this.pos.x = this.posX;
		this.pos.y = this.posY;
		this.foundValue = false;
		this.p = _p.cloned();
	}

	/**
	 * 
	 * @param _cycles
	 *            number of cycles to reach the ball
	 * @param _p
	 *            the player who wants to reach something
	 * @param _reachDist
	 *            distance in that the ball can be catched / kicked directly
	 */
	public ReachableArea(int _cycles, Player _p, double _reachDist) {
		this.dummyPlayer = _p.cloned();
		this.dummyPlayer.extrapolate(_cycles,
				this.dummyPlayer.getPConf().PLAYER_DECAY);
		this.cycles = _cycles;
		this.reactCycles = 0;
		this.posX = this.dummyPlayer.getPosition().x;
		this.posY = this.dummyPlayer.getPosition().y;
		this.bodyDir = this.dummyPlayer.getBodyDir();
		this.turn1 = getTurnFromArg(180, _p);
		this.dummyPlayer.copy(_p);
		this.dummyPlayer.extrapolate(1,
				this.dummyPlayer.getPConf().PLAYER_DECAY);
		this.turn2 = getTurnFromArg(180, this.dummyPlayer) + this.turn1;
		this.dummyPlayer.extrapolate(1,
				this.dummyPlayer.getPConf().PLAYER_DECAY);
		this.turn3 = getTurnFromArg(180, this.dummyPlayer) + this.turn2;
		if (this.turn1 > 180) {
			this.turn1 = 181;
		}
		if (this.turn2 > 180) {
			this.turn2 = 181;
		}
		if (this.turn3 > 180) {
			this.turn3 = 181;
		}
		this.dummyPlayer.setSpeed(new Vektor(0, 0));
		this.dummyPlayer.setPosition(new Vektor(0, 0));
		this.dummyPlayer.setBodyDir(0);
		this.dash0 = 0;
		this.dash1 = 0;
		this.dash2 = 0;
		this.dash3 = 0;
		this.dash4 = 0;
		for (int i = this.cycles - 1 - this.reactCycles; i >= 0; i--) {
			this.dummyPlayer.predictThisAfterAction(DASH_100);
			if (i == 4) {
				this.dash4 = this.dummyPlayer.getPosition().y;
			}
			if (i == 3) {
				this.dash3 = this.dummyPlayer.getPosition().y;
			}
			if (i == 2) {
				this.dash2 = this.dummyPlayer.getPosition().y;
			}
			if (i == 1) {
				this.dash1 = this.dummyPlayer.getPosition().y;
			}
			if (i == 0) {
				this.dash0 = this.dummyPlayer.getPosition().y;
			}
		}
		this.reachDist = _reachDist;
		this.pos.x = this.posX;
		this.pos.y = this.posY;
		this.foundValue = false;
		this.p = _p.cloned();
	}

	/**
	 * creates a not initialized ReachableArea
	 */
	public ReachableArea() {
		this.reactCycles = 0;
		this.cycles = 0;
		this.posX = 0;
		this.posY = 0;
		this.bodyDir = 0;
		this.turn1 = 0;
		this.turn2 = 0;
		this.dash0 = 0;
		this.turn3 = 0;
		this.dash4 = 0;
		this.dash1 = 0;
		this.dash2 = 0;
		this.dash3 = 0;
		this.reachDist = 0;
		this.foundValue = false;
		this.p = new Player(0, 0, 0, new Vektor(0, 0), new Vektor(0, 0), 0, 0,
				0, 0, 0, false, false, false, new PConf());
		this.dummyPlayer = new Player(0, 0, 0, new Vektor(0, 0), new Vektor(0,
				0), 0, 0, 0, 0, 0, false, false, false, new PConf());
	}

	/**
   * set the cycles
	 * @param c
	 */
	public void setCycles(int c) {
		this.cycles = c;
	}

	/**
   * set the x-value of the position
	 * @param x the x-value of the position
	 */
	public void setPosX(double x) {
		this.posX = x;
		this.pos.x = this.posX;
	}

	/**
   * set the y-value of the position
	 * @param y the y-value of the position
	 */
	public void setPosY(double y) {
		this.posY = y;
		this.pos.y = this.posY;
	}

	/**
   * set the position
	 * @param _pos the position
	 */
	public void setPos(Vektor _pos) {
		this.posX = _pos.x;
		this.posY = _pos.y;
		this.pos.x = this.posX;
		this.pos.y = this.posY;
	}

	/**
   * the the bodydir
	 * @param d the bodydir
	 */
	public void setBodyDir(double d) {
		this.bodyDir = d;
	}

  /**
   * how far can I turn after 1 turn-action
   * @param t the angle
   */
	public void setTurn1(double t) {
		this.turn1 = abs(t);
		if (this.turn1 > 180) {
			this.turn1 = 181;
		}
	}


  /**
   * how far can I turn after 3 turn-actions
   * @param t the angle
   */
	public void setTurn3(double t) {
		this.turn3 = abs(t);
		if (this.turn3 > 180) {
			this.turn3 = 181;
		}
	}


  /**
   * how far can I turn after 2 turn-actions
   * @param t the angle
   */
	public void setTurn2(double t) {
		this.turn2 = abs(t);
		if (this.turn1 > 180) {
			this.turn1 = 181;
		}
	}

  /**
   * how far can I dash after cycles - 4 dashes?
   * @param d the distance
   */
	public void setDash4(double d) {
		this.dash4 = d;
	}

  /**
   * how far can I dash after cycles dashes?
   * @param d the distance
   */
	public void setDash0(double d) {
		this.dash0 = d;
	}

  /**
   * how far can I dash after cycles - 1 dashes?
   * @param d the distance
   */
	public void setDash1(double d) {
		this.dash1 = d;
	}

  /**
   * how far can I dash after cycles - 2 dashes?
   * @param d the distance
   */
	public void setDash2(double d) {
		this.dash2 = d;
	}

  /**
   * how far can I dash after cycles - 3 dashes?
   * @param d the distance
   */
	public void setDash3(double d) {
		this.dash3 = d;
	}

  /**
   * how close I have to come to my point (rest is made by (kickdist normally)
   * @param d the distance
   */
	public void setReachDist(double d) {
		this.reachDist = d;
	}

  /**
   * set the cycles with no reation is made (calculated a only drifting)
   * @param d the cycles
   */
	public void setReactCycles(int d) {
		this.reactCycles = d;
	}

	/**
   * Set the player.
	 * @param _p the player
	 */
	public void setPlayer(Player _p) {
		if (_p != null) {
			this.p.copy(_p);
		}
	}

	/**
	 * @return the cycles
	 */
	public int getCycles() {
		return this.cycles;
	}

	/**
	 * @return the  x-value of the position
	 */
	public double getPosX() {
		return this.posX;
	}

	/**
	 * @return the y-value of the position
	 */
	public double getPosY() {
		return this.posY;
	}

	/**
	 * @return the position (new vektor)
	 */
	public Vektor getPos() {
		return new Vektor(XY, this.posX, this.posY);
	}

	/**
	 * @return the bodydir
	 */
	public double getBodyDir() {
		return this.bodyDir;
	}

	/**
	 * @return the turn1
	 */
	public double getTurn1() {
		return this.turn1;
	}

	/**
	 * @return the turn3
	 */
	public double getTurn3() {
		return this.turn3;
	}

	/**
	 * @return the turn2
	 */
	public double getTurn2() {
		return this.turn2;
	}

	/**
	 * @return the dash0
	 */
	public double getDash0() {
		return this.dash0;
	}

	/**
	 * @return the dash4
	 */
	public double getDash4() {
		return this.dash4;
	}

	/**
	 * @return the dash1
	 */
	public double getDash1() {
		return this.dash1;
	}

	/**
	 * @return the dash2
	 */
	public double getDash2() {
		return this.dash2;
	}

	/**
	 * @return the dash3
	 */
	public double getDash3() {
		return this.dash3;
	}

	/**
	 * @return the reachdist
	 */
	public double getReachDist() {
		return this.reachDist;
	}

	/**
	 * @return the reactcycles
	 */
	public int getReactCycles() {
		return this.reactCycles;
	}

	/**
	 * @return a clone of the player
	 */
	public Player getPlayerClone() {
		return this.p.cloned();
	}

	/**
	 * @return true if a calculation found a value
	 */
	public boolean foundValue() {
		return this.foundValue;
	}

	/**
	 * 
	 * @param _cycles
	 *            number of cycles to reach the ball
	 * @param _reactCycles
	 *            number of cycles until movement begins
	 * @param _p
	 *            the player who wants to reach something
	 * @param _reachDist
	 *            distance in that the ball can be catched / kicked directly
	 */
	public void setArea(int _cycles, int _reactCycles, Player _p,
			double _reachDist) {
		// debugReachOut("-------------set area------------------");
		// debugReachOut("Player "+_p.getNumber());
		this.dummyPlayer.copy(_p);
		this.p.copy(_p);
		this.dummyPlayer.extrapolate(_cycles,
				this.dummyPlayer.getPConf().PLAYER_DECAY);
		this.cycles = _cycles;
		// debugReachOut("cycles "+cycles);
		this.reactCycles = _reactCycles;
		// debugReachOut("react time "+reactCycles);
		this.posX = this.dummyPlayer.getPosition().x;
		this.posY = this.dummyPlayer.getPosition().y;
		// debugReachOut("extr. x "+posX);
		// debugReachOut("extr. y "+posY);
		this.bodyDir = this.dummyPlayer.getBodyDir();
		// debugReachOut("bodyDir "+bodyDir);
		this.turn1 = getTurnFromArg(180, _p);
		this.dummyPlayer.copy(_p);
		this.dummyPlayer.extrapolate(1,
				this.dummyPlayer.getPConf().PLAYER_DECAY);
		this.turn2 = getTurnFromArg(180, this.dummyPlayer) + this.turn1;
		this.dummyPlayer.extrapolate(1,
				this.dummyPlayer.getPConf().PLAYER_DECAY);
		this.turn3 = getTurnFromArg(180, this.dummyPlayer) + this.turn2;
		if (this.turn1 > 180) {
			this.turn1 = 181;
		}
		if (this.turn2 > 180) {
			this.turn2 = 181;
		}
		if (this.turn3 > 180) {
			this.turn3 = 181;
		}
		// debugReachOut("turn1 "+turn1);
		// debugReachOut("turn2 "+turn2);
		// debugReachOut("turn3 "+turn3);
		// debugReachOut("--reset dummyplayer--");
		this.dummyPlayer.setSpeed(new Vektor(0, 0));
		this.dummyPlayer.setPosition(new Vektor(0, 0));
		this.dummyPlayer.setBodyDir(0);
		this.dash0 = 0;
		this.dash1 = 0;
		this.dash2 = 0;
		this.dash3 = 0;
		this.dash4 = 0;
		// debugReachOut("start loop");
		for (int i = this.cycles - 1 - this.reactCycles; i >= 0; i--) {
			// debugReachOut("i "+i);
			this.dummyPlayer.predictThisAfterAction(DASH_100);
			if (i == 4) {
				this.dash4 = this.dummyPlayer.getPosition().y;
				// debugReachOut("dash4 "+dash4);
			}
			if (i == 3) {
				this.dash3 = this.dummyPlayer.getPosition().y;
				// debugReachOut("dash3 "+dash3);
			}
			if (i == 2) {
				this.dash2 = this.dummyPlayer.getPosition().y;
				// debugReachOut("dash2 "+dash2);
			}
			if (i == 1) {
				this.dash1 = this.dummyPlayer.getPosition().y;
				// debugReachOut("dash1 "+dash1);
			}
			if (i == 0) {
				this.dash0 = this.dummyPlayer.getPosition().y;
				// debugReachOut("dash0 "+dash0);
			}
		}
		this.reachDist = _reachDist;
		// debugReachOut("reachDist "+reachDist);
		this.pos.x = this.posX;
		this.pos.y = this.posY;
		this.foundValue = false;
	}

	/**
	 * 
	 * @param _cycles
	 *            number of cycles to reach the ball
	 * @param _p
	 *            the player who wants to reach something
	 * @param _reachDist
	 *            distance in that the ball can be catched / kicked directly
	 */
	public void setArea(int _cycles, Player _p, double _reachDist) {
		setArea(_cycles, 0, _p, _reachDist);
	}

	/**
   * Copies another ReachableArea into this one
	 * @param ra the ReachableArea to copy
	 */
	public void copy(ReachableArea ra) {
		this.cycles = ra.getCycles();
		this.reactCycles = ra.getReactCycles();
		this.posX = ra.getPosX();
		this.posY = ra.getPosY();
		this.bodyDir = ra.getBodyDir();
		this.turn1 = ra.getTurn1();
		this.turn2 = ra.getTurn2();
		this.dash0 = ra.getDash0();
		this.turn3 = ra.getTurn3();
		this.dash4 = ra.getDash4();
		this.dash1 = ra.getDash1();
		this.dash2 = ra.getDash2();
		this.dash3 = ra.getDash3();
		this.reachDist = ra.getReachDist();
		this.foundValue = false;
		this.p = ra.getPlayerClone();
	}

	/**
	 * 
	 * @param p
	 *            position to test
	 * @return true if the given position is reachable by turns and forward
	 *         dashing
	 */
	public boolean inArea(Vektor p) {
		return inArea(p, 0);
	}

	/**
	 * 
	 * @param p
	 *            position to test
	 * @param backwards
	 *            if true, also backwards-movement is allowed
	 * @return true if the given position is reachable by turns and dashing
	 */
	public boolean inArea(Vektor p, boolean backwards) {
    if (backwards) {
      return inArea(p, -1);
    }
    return inArea(p, 0);
	}

	/**
	 * 
	 * @param p
	 *            position to test
	 * @param backcycles
	 *            maximum number of cycles to move backwards
   *            -1 if no maximum is needed (backward is allowed always)
	 * @return true if the point is reachable
	 */
	public boolean inArea(Vektor p, int backcycles) {
		double dist = this.pos.getDistance(p);
		double backDist = 0;
		this.dummyPlayer.setPosition(new Vektor(0, 0));
		this.dummyPlayer.setSpeed(new Vektor(0, 0));
		this.dummyPlayer.setBodyDir(0);
		for (int i = 0; i < backcycles; i++) {
			this.dummyPlayer.predictThisAfterAction(ReachableArea.DASH_100);
		}
		backDist = this.dummyPlayer.getPosition().y;
		if (backcycles < 0) {
			backDist = 100;
		}
		double angle = normalize(this.pos.getAngleTo(p) - this.bodyDir);
		if (dist < this.dash4 + this.reachDist) {
			return true;
		}
		if (dist >= this.dash0 + this.reachDist) {
			return false;
		}
		if (abs(angle) < this.turn3
				&& this.pos.getDistance(p) < this.dash3 + this.reachDist) {
			return true;
		}
		if (abs(angle) < this.turn2
				&& this.pos.getDistance(p) < this.dash2 + this.reachDist) {
			return true;
		}
		if (abs(angle) < this.turn1
				&& this.pos.getDistance(p) < this.dash1 + this.reachDist) {
			return true;
		}
		if (abs(asin(this.reachDist / dist) * 180 / PI) > abs(angle)) {
			return true;
		}
		angle = normalize(angle + 180);
		if (abs(angle) < this.turn3
				&& this.pos.getDistance(p) < this.dash3 + this.reachDist
				&& this.pos.getDistance(p) < backDist + this.reachDist) {
			return true;
		}
		if (abs(angle) < this.turn2
				&& this.pos.getDistance(p) < this.dash2 + this.reachDist
				&& this.pos.getDistance(p) < backDist + this.reachDist) {
			return true;
		}
		if (abs(angle) < this.turn1
				&& this.pos.getDistance(p) < this.dash1 + this.reachDist
				&& this.pos.getDistance(p) < backDist + this.reachDist) {
			return true;
		}
		if (abs(asin(this.reachDist / dist) * 180 / PI) > abs(angle)
				&& this.pos.getDistance(p) < backDist + this.reachDist) {
			return true;
		}
		return false;
	}

	/**
	 * 
	 * @param pos
	 *            the position to reach
	 * @param reachedDist
	 *            how close I have to come to the target-position
	 * @param turnBuffer
	 *            if the turnangle is smaller than turnbuffer, no turn is
	 *            performed to save time
	 * @param backwards
	 *            if this is true, then the player checks if it is faster to
	 *            come backwards to the desired position otherwise the player
	 *            runs definitely forward
	 * @param backCycles
	 *            gives a maximum number of cycles to dash backward (because of
	 *            high stamina costs) if "backwards" is false, this has no
	 *            effect if backCycles is smaller than 0, it will be ignored
	 * @param watchPos
	 *            gives a position that should be watchable during all movements
	 *            and influences in this way the decision to move backward or
	 *            not.
	 * 
	 * sometimes the position is watchable only for a few cycles during the move
	 * in this case the pos is watchable during the first moves of the list
	 * 
	 * if it is null, it will be ignored if "backwards" is false, watchPos will
	 * be ignored
	 * @param turnToPos
	 *            after all movements are done, the player will turn his body to
	 *            this position if null, no turn will be performed after the
	 *            normal moves
	 * @return a list of movements to reach the given position as fast as
	 *         possible under the given conditions
	 */
	public LinkedList<Action> getMovesToPos(Vektor pos, double reachedDist,
			double turnBuffer, boolean backwards, int backCycles,
			Vektor watchPos, Vektor turnToPos) {
		// this.debugMovesOut("start calculating moves");
		LinkedList<Action> list = new LinkedList<Action>();
		if (!backwards) {
			// this.debugMovesOut("FORWARD DEFINITELY");
			backCycles = 0;
			watchPos = null;
		}
		double backDist = 0;
		if (backCycles < 0) {
			// this.debugMovesOut("no backcycles");
			backDist = 100;
		} else {
			this.dummyPlayer.setPosition(new Vektor(0, 0));
			this.dummyPlayer.setSpeed(new Vektor(0, 0));
			this.dummyPlayer.setBodyDir(0);
			for (int i = 0; i < backCycles; i++) {
				this.dummyPlayer.predictThisAfterAction(ReachableArea.DASH_100);
			}
			backDist = this.dummyPlayer.getPosition().y;
		}
		// find extrapolated position
		this.dummyPlayer.copy(this.p);
		this.dummyPlayer.extrapolate(this.cycles,
				this.p.getPConf().PLAYER_DECAY);
		this.dummyVektor.copy(this.dummyPlayer.getPosition());
		double dist2pos = this.dummyVektor.getDistance(pos);
		double angle2pos = normalize(this.dummyVektor.getAngleTo(pos)
				- this.bodyDir);
		double angle2watchPos = 0;
		if (watchPos != null) {
			// this.debugMovesOut("using watchpos");
			angle2watchPos = normalize(this.dummyVektor.getAngleTo(watchPos)
					- this.bodyDir);
		}
		if (backDist < dist2pos) {
			// this.debugMovesOut("not backwards because of backcycles");
			backwards = false;
		}
		if (watchPos != null) {
			if (abs(normalize(angle2watchPos - angle2pos)) < 90) {
				// this.debugMovesOut("not backwards because of watchposition");
				backwards = false;
			}
		} else {
			// no watchpos
			if (abs(angle2pos) <= this.turn1) {
				// this.debugMovesOut("not beackwards because of turnangle");
				backwards = false;
			} else if (abs(angle2pos) <= this.turn2
					&& abs(normalize(angle2pos + 180)) > this.turn1) {
				// this.debugMovesOut("not beackwards because of turnangle");
				backwards = false;
			} else if (abs(angle2pos) <= this.turn3
					&& abs(normalize(angle2pos + 180)) > this.turn2) {
				// this.debugMovesOut("not beackwards because of turnangle");
				backwards = false;
			} else if (abs(normalize(angle2pos + 180)) > this.turn3) {
				// this.debugMovesOut("not beackwards because of turnangle");
				backwards = false;
			}
		}
		this.dummyPlayer.copy(this.p);
		// this.debugMovesOut("backwards: "+backwards);
		// no we know if to dash backward or not
		// this.debugMovesOut("already reached pos: "+(dist2pos <=
		// reachedDist));
		if (dist2pos > reachedDist) {
			if (!backwards) {
				// begin forward
				if (abs(angle2pos) <= this.turn1) {
					// start 1 turn
					if (abs(angle2pos) > turnBuffer) {
						// this.debugMovesOut("turn: "+getTurnArg(angle2pos,
						// p));
						TurnAction t1 = new TurnAction(getTurnArg(angle2pos,
								this.p));
						list.add(t1);
						this.dummyPlayer.predictThisAfterAction(t1);
					}
					// end 1 turn
				} else if (abs(angle2pos) <= this.turn2) {
					// start 2 turns
					if (angle2pos > 0) {
						// this.debugMovesOut("turn: 180");
						TurnAction t1 = new TurnAction(180);
						list.add(t1);
						this.dummyPlayer.predictThisAfterAction(t1);
						angle2pos -= this.turn1;
					} else {
						// this.debugMovesOut("turn: -180");
						TurnAction t1 = new TurnAction(-180);
						list.add(t1);
						this.dummyPlayer.predictThisAfterAction(t1);
						angle2pos += this.turn1;
					}
					if (abs(angle2pos) > turnBuffer) {
						// this.debugMovesOut("turn: "+getTurnArg(angle2pos,
						// p));
						TurnAction t2 = new TurnAction(getTurnArg(angle2pos,
								this.p));
						list.add(t2);
						this.dummyPlayer.predictThisAfterAction(t2);
					}
					// end 2 turns
				} else if (abs(angle2pos) <= this.turn3) {
					// start 3 turns
					if (angle2pos > 0) {
						TurnAction t1 = new TurnAction(180);
						list.add(t1);
						this.dummyPlayer.predictThisAfterAction(t1);
						// this.debugMovesOut("turn: 180");
						TurnAction t2 = new TurnAction(180);
						list.add(t2);
						this.dummyPlayer.predictThisAfterAction(t2);
						// this.debugMovesOut("turn: 180");
						angle2pos -= this.turn2;
					} else {
						TurnAction t1 = new TurnAction(-180);
						list.add(t1);
						this.dummyPlayer.predictThisAfterAction(t1);
						// this.debugMovesOut("turn: -180");
						TurnAction t2 = new TurnAction(-180);
						list.add(t2);
						this.dummyPlayer.predictThisAfterAction(t2);
						// this.debugMovesOut("turn: -180");
						angle2pos += this.turn2;
					}
					if (abs(angle2pos) > turnBuffer) {
						// this.debugMovesOut("turn: "+getTurnArg(angle2pos,
						// p));
						TurnAction t3 = new TurnAction(getTurnArg(angle2pos,
								this.p));
						list.add(t3);
						this.dummyPlayer.predictThisAfterAction(t3);
					}
					// end 3 turns
				} else {
					// start 4 turns
					if (angle2pos > 0) {
						TurnAction t1 = new TurnAction(180);
						list.add(t1);
						this.dummyPlayer.predictThisAfterAction(t1);
						// this.debugMovesOut("turn: 180");
						TurnAction t2 = new TurnAction(180);
						list.add(t2);
						this.dummyPlayer.predictThisAfterAction(t2);
						// this.debugMovesOut("turn: 180");
						TurnAction t3 = new TurnAction(180);
						list.add(t3);
						this.dummyPlayer.predictThisAfterAction(t3);
						// //this.debugMovesOut("turn: 180");
						angle2pos -= this.turn3;
					} else {
						TurnAction t1 = new TurnAction(-180);
						list.add(t1);
						dummyPlayer.predictThisAfterAction(t1);
						// this.debugMovesOut("turn: -180");
						TurnAction t2 = new TurnAction(-180);
						list.add(t2);
						dummyPlayer.predictThisAfterAction(t2);
						// this.debugMovesOut("turn: -180");
						TurnAction t3 = new TurnAction(-180);
						list.add(t3);
						dummyPlayer.predictThisAfterAction(t3);
						// this.debugMovesOut("turn: -180");
						angle2pos += turn3;
					}
					if (abs(angle2pos) > turnBuffer) {
						TurnAction t4 = new TurnAction(getTurnArg(angle2pos, p));
						// this.debugMovesOut("turn: "+getTurnArg(angle2pos,
						// p));
						list.add(t4);
						dummyPlayer.predictThisAfterAction(t4);
					}
					// end 4 turns
				}
				// begin dashes
				boolean reached = false;
				double actspeed = 0;
				double decay = dummyPlayer.getPConf().PLAYER_DECAY;
				double dpr = dummyPlayer.getPConf().DASH_POWER_RATE;
				double decaydist = 0;
				double actdist = 0;
				double newdist = 0;
				while (!reached) {
					actspeed = dummyPlayer.getSpeed().getLength();
					decaydist = actspeed + (decay * actspeed)
							+ (decay * decay * actspeed);
					actdist = dummyPlayer.getDistance(pos);
					if (actdist > decaydist + reachedDist) {
						DashAction d = new DashAction(100);
						list.add(d);
						// this.debugMovesOut("dash: 100");
						dummyPlayer.predictThisAfterAction(d);
						newdist = dummyPlayer.getDistance(pos);
						if (newdist > actdist) {
							reached = true;
						}
					} else {
						int dashpower = (int) round((actdist - decaydist)
								/ ((1 + decay + decay * decay) * dpr));
						dashpower = max(-100, min(100, dashpower));
						// this.debugMovesOut("dash: "+dashpower);
						DashAction d = new DashAction(dashpower);
						list.add(d);
						dummyPlayer.predictThisAfterAction(d);
						reached = true;
					}
				}
				// end forward
			} else {
				// begin backward
				angle2pos = normalize(angle2pos + 180);
				if (abs(angle2pos) <= turn1) {
					// start 1 turn
					if (abs(angle2pos) > turnBuffer) {
						// this.debugMovesOut("turn: "+getTurnArg(angle2pos,
						// p));
						TurnAction t1 = new TurnAction(getTurnArg(angle2pos, p));
						list.add(t1);
						dummyPlayer.predictThisAfterAction(t1);
					}
					// end 1 turn
				} else if (abs(angle2pos) <= turn2) {
					// start 2 turns
					if (angle2pos > 0) {
						TurnAction t1 = new TurnAction(180);
						list.add(t1);
						// this.debugMovesOut("turn: 180");
						dummyPlayer.predictThisAfterAction(t1);
						angle2pos -= turn1;
					} else {
						TurnAction t1 = new TurnAction(-180);
						list.add(t1);
						// this.debugMovesOut("turn: -180");
						dummyPlayer.predictThisAfterAction(t1);
						angle2pos += turn1;
					}
					if (abs(angle2pos) > turnBuffer) {
						// this.debugMovesOut("turn: "+getTurnArg(angle2pos,
						// p));
						TurnAction t2 = new TurnAction(getTurnArg(angle2pos, p));
						list.add(t2);
						dummyPlayer.predictThisAfterAction(t2);
					}
					// end 2 turns
				} else if (abs(angle2pos) <= turn3) {
					// start 3 turns
					if (angle2pos > 0) {
						TurnAction t1 = new TurnAction(180);
						list.add(t1);
						// this.debugMovesOut("turn: 180");
						dummyPlayer.predictThisAfterAction(t1);
						TurnAction t2 = new TurnAction(180);
						list.add(t2);
						// this.debugMovesOut("turn: 180");
						dummyPlayer.predictThisAfterAction(t2);
						angle2pos -= turn2;
					} else {
						TurnAction t1 = new TurnAction(-180);
						list.add(t1);
						// this.debugMovesOut("turn: -180");
						dummyPlayer.predictThisAfterAction(t1);
						TurnAction t2 = new TurnAction(-180);
						list.add(t2);
						// this.debugMovesOut("turn: -180");
						dummyPlayer.predictThisAfterAction(t2);
						angle2pos += turn2;
					}
					if (abs(angle2pos) > turnBuffer) {
						// this.debugMovesOut("turn: "+getTurnArg(angle2pos,
						// p));
						TurnAction t3 = new TurnAction(getTurnArg(angle2pos, p));
						list.add(t3);
						dummyPlayer.predictThisAfterAction(t3);
					}
					// end 3 turns
				} else {
					// start 4 turns
					if (angle2pos > 0) {
						TurnAction t1 = new TurnAction(180);
						list.add(t1);
						// this.debugMovesOut("turn: 180");
						dummyPlayer.predictThisAfterAction(t1);
						TurnAction t2 = new TurnAction(180);
						list.add(t2);
						// this.debugMovesOut("turn: 180");
						dummyPlayer.predictThisAfterAction(t2);
						TurnAction t3 = new TurnAction(180);
						list.add(t3);
						// this.debugMovesOut("turn: 180");
						dummyPlayer.predictThisAfterAction(t3);
						angle2pos -= turn3;
					} else {
						TurnAction t1 = new TurnAction(-180);
						list.add(t1);
						// this.debugMovesOut("turn: -180");
						dummyPlayer.predictThisAfterAction(t1);
						TurnAction t2 = new TurnAction(-180);
						list.add(t2);
						// this.debugMovesOut("turn: -180");
						dummyPlayer.predictThisAfterAction(t2);
						TurnAction t3 = new TurnAction(-180);
						list.add(t3);
						// this.debugMovesOut("turn: -180");
						dummyPlayer.predictThisAfterAction(t3);
						angle2pos += turn3;
					}
					if (abs(angle2pos) > turnBuffer) {
						// this.debugMovesOut("turn: "+getTurnArg(angle2pos,
						// p));
						TurnAction t4 = new TurnAction(getTurnArg(angle2pos, p));
						list.add(t4);
						dummyPlayer.predictThisAfterAction(t4);
					}
					// end 4 turns
				}
				// begin dashes
				boolean reached = false;
				double actspeed = 0;
				double decay = dummyPlayer.getPConf().PLAYER_DECAY;
				double dpr = dummyPlayer.getPConf().DASH_POWER_RATE;
				double decaydist = 0;
				double actdist = 0;
				double newdist = 0;
				while (!reached) {
					actspeed = dummyPlayer.getSpeed().getLength();
					decaydist = actspeed + (decay * actspeed)
							+ (decay * decay * actspeed);
					actdist = dummyPlayer.getDistance(pos);
					if (actdist > decaydist + reachedDist) {
						// this.debugMovesOut("big dist");
						DashAction d = new DashAction(-100);
						list.add(d);
						// this.debugMovesOut("dash: -100");
						dummyPlayer.predictThisAfterAction(d);
						newdist = dummyPlayer.getDistance(pos);
						if (newdist > actdist) {
							reached = true;
						}
					} else {
						// this.debugMovesOut("last dash");
						int dashpower = -(int) round((actdist - decaydist)
								/ ((1 + decay + decay * decay) * dpr));
						dashpower = max(-100, min(100, dashpower));
						// this.debugMovesOut("dash: "+dashpower);
						DashAction d = new DashAction(dashpower);
						list.add(d);
						dummyPlayer.predictThisAfterAction(d);
						reached = true;
					}
				}
				// end backward
			}
			// end not in reached dist
		}
		// this.debugMovesOut("turn to desired pos");
		// turn to desired pos
		if (turnToPos != null) {
			angle2pos = normalize(dummyPlayer.getAngleTo(turnToPos) - bodyDir);
			if (abs(angle2pos) <= turn1) {
				// start 1 turn
				if (abs(angle2pos) > turnBuffer) {
					// this.debugMovesOut("turn: "+getTurnArg(angle2pos, p));
					TurnAction t1 = new TurnAction(getTurnArg(angle2pos, p));
					list.add(t1);
					dummyPlayer.predictThisAfterAction(t1);
				}
				// end 1 turn
			} else if (abs(angle2pos) <= turn2) {
				// start 2 turns
				if (angle2pos > 0) {
					// this.debugMovesOut("turn: 180");
					TurnAction t1 = new TurnAction(180);
					list.add(t1);
					dummyPlayer.predictThisAfterAction(t1);
					angle2pos -= turn1;
				} else {
					// this.debugMovesOut("turn: -180");
					TurnAction t1 = new TurnAction(-180);
					list.add(t1);
					dummyPlayer.predictThisAfterAction(t1);
					angle2pos += turn1;
				}
				if (abs(angle2pos) > turnBuffer) {
					// this.debugMovesOut("turn: "+getTurnArg(angle2pos, p));
					TurnAction t2 = new TurnAction(getTurnArg(angle2pos, p));
					list.add(t2);
					dummyPlayer.predictThisAfterAction(t2);
				}
				// end 2 turns
			} else if (abs(angle2pos) <= turn3) {
				// start 3 turns
				if (angle2pos > 0) {
					// this.debugMovesOut("turn: 180");
					TurnAction t1 = new TurnAction(180);
					list.add(t1);
					dummyPlayer.predictThisAfterAction(t1);
					// this.debugMovesOut("turn: 180");
					TurnAction t2 = new TurnAction(180);
					list.add(t2);
					dummyPlayer.predictThisAfterAction(t2);
					angle2pos -= turn2;
				} else {
					// this.debugMovesOut("turn: -180");
					TurnAction t1 = new TurnAction(-180);
					list.add(t1);
					dummyPlayer.predictThisAfterAction(t1);
					// this.debugMovesOut("turn: -180");
					TurnAction t2 = new TurnAction(-180);
					list.add(t2);
					dummyPlayer.predictThisAfterAction(t2);
					angle2pos += turn2;
				}
				if (abs(angle2pos) > turnBuffer) {
					// this.debugMovesOut("turn: "+getTurnArg(angle2pos, p));
					TurnAction t3 = new TurnAction(getTurnArg(angle2pos, p));
					list.add(t3);
					dummyPlayer.predictThisAfterAction(t3);
				}
				// end 3 turns
			} else {
				// start 4 turns
				if (angle2pos > 0) {
					// this.debugMovesOut("turn: 180");
					TurnAction t1 = new TurnAction(180);
					list.add(t1);
					dummyPlayer.predictThisAfterAction(t1);
					// this.debugMovesOut("turn: 180");
					TurnAction t2 = new TurnAction(180);
					list.add(t2);
					dummyPlayer.predictThisAfterAction(t2);
					// this.debugMovesOut("turn: 180");
					TurnAction t3 = new TurnAction(180);
					list.add(t3);
					dummyPlayer.predictThisAfterAction(t3);
					angle2pos -= turn3;
				} else {
					// this.debugMovesOut("turn: -180");
					TurnAction t1 = new TurnAction(-180);
					list.add(t1);
					dummyPlayer.predictThisAfterAction(t1);
					// this.debugMovesOut("turn: -180");
					TurnAction t2 = new TurnAction(-180);
					list.add(t2);
					dummyPlayer.predictThisAfterAction(t2);
					// this.debugMovesOut("turn: -180");
					TurnAction t3 = new TurnAction(-180);
					list.add(t3);
					dummyPlayer.predictThisAfterAction(t3);
					angle2pos += turn3;
				}
				if (abs(angle2pos) > turnBuffer) {
					// this.debugMovesOut("turn: "+getTurnArg(angle2pos, p));
					TurnAction t4 = new TurnAction(getTurnArg(angle2pos, p));
					list.add(t4);
					dummyPlayer.predictThisAfterAction(t4);
				}
				// end 4 turns
			}
		}
		if (list.size() == 0) {
			TurnAction t = new TurnAction(0);
			// this.debugMovesOut("no action, add turn 0");
			list.add(t);
		}
		return list;
	}

	/**
	 * 
	 * @param pos
	 *            the position to reach
	 * @param reachedDist
	 *            how close I have to come to the target-position
	 * @param turnBuffer
	 *            if the turnangle is smaller than turnbuffer, no turn is
	 *            performed to save time
	 * @param backwards
	 *            if this is true, then the player checks if it is faster to
	 *            come backwards to the desired position otherwise the player
	 *            runs definitely forward
	 * @param backCycles
	 *            gives a maximum number of cycles to dash backward (because of
	 *            high stamina costs) if "backwards" is false, this has no
	 *            effect if backCycles is smaller than 0, it will be ignored
	 * @param watchPos
	 *            gives a position that should be watchable during all movements
	 *            and influences in this way the decision to move backward or
	 *            not.
	 * 
	 * sometimes the position is watchable only for a few cycles during the move
	 * in this case the pos is watchable during the first moves of the list
	 * 
	 * if it is null, it will be ignored if "backwards" is false, watchPos will
	 * be ignored
	 * @param turnToPos
	 *            after all movements are done, the player will turn his body to
	 *            this position if null, no turn will be performed after the
	 *            normal moves
	 * @return a list of movements to reach the given position as fast as
	 *         possible under the given conditions
	 */
	public Action getFirstMoveToPos(Vektor pos, double reachedDist,
			double turnBuffer, boolean backwards, int backCycles,
			Vektor watchPos, Vektor turnToPos) {
		// this.debugMovesOut("start calculating moves");
		// LinkedList<Action> list= new LinkedList<Action>();
		if (!backwards) {
			// this.debugMovesOut("FORWARD DEFINITELY");
			backCycles = 0;
			watchPos = null;
		}
		double backDist = 0;
		if (backCycles < 0) {
			// this.debugMovesOut("no backcycles");
			backDist = 100;
		} else {
			dummyPlayer.setPosition(new Vektor(0, 0));
			dummyPlayer.setSpeed(new Vektor(0, 0));
			dummyPlayer.setBodyDir(0);
			for (int i = 0; i < backCycles; i++) {
				dummyPlayer.predictThisAfterAction(DASH_100);
			}
			backDist = dummyPlayer.getPosition().y;
		}
		// find extrapolated position
		dummyPlayer.copy(p);
		dummyPlayer.extrapolate(cycles, p.getPConf().PLAYER_DECAY);
		dummyVektor.copy(dummyPlayer.getPosition());
		double dist2pos = dummyVektor.getDistance(pos);
		double angle2pos = dummyPlayer.getAngleRel(pos, RELATIVE.TO_BODY);
		double angle2watchPos = 0;
		if (watchPos != null) {
			// this.debugMovesOut("using watchpos");
			angle2watchPos = normalize(dummyVektor.getAngleTo(watchPos)
					- bodyDir);
		}
		if (backDist < dist2pos) {
			// this.debugMovesOut("not backwards because of backcycles");
			backwards = false;
		}
		if (watchPos != null && backwards) {
			if (abs(normalize(angle2watchPos - angle2pos)) < 90) {
				// this.debugMovesOut("not backwards because of watchposition");
				backwards = false;
			}
		} else {
			// no watchpos
			if (abs(angle2pos) <= turn1) {
				// this.debugMovesOut("not beackwards because of turnangle");
				backwards = false;
			} else if (abs(angle2pos) <= turn2
					&& abs(normalize(angle2pos + 180)) > turn1) {
				// this.debugMovesOut("not beackwards because of turnangle");
				backwards = false;
			} else if (abs(angle2pos) <= turn3
					&& abs(normalize(angle2pos + 180)) > turn2) {
				// this.debugMovesOut("not beackwards because of turnangle");
				backwards = false;
			} else if (abs(normalize(angle2pos + 180)) > turn3) {
				// this.debugMovesOut("not beackwards because of turnangle");
				backwards = false;
			}
		}
		dummyPlayer.copy(p);
		// this.debugMovesOut("backwards: "+backwards);
		// no we know if to dash backward or not
		// this.debugMovesOut("already reached pos: "+(dist2pos <=
		// reachedDist));
		if (dist2pos > reachedDist) {
			if (!backwards) {
				if (abs(angle2pos) > turn2 && p.getStamina() > 2800) {
					return BasicActionFactory.dashToPoint(p, p.getPosition());
				}
				// begin forward
				if (abs(angle2pos) <= turn1) {
					// start 1 turn
					if (abs(angle2pos) > turnBuffer) {
						// this.debugMovesOut("turn: "+getTurnArg(angle2pos,
						// p));
						TurnAction t1 = new TurnAction(getTurnArg(angle2pos, p));
						return t1;
					}
					// end 1 turn
				} else if (abs(angle2pos) <= turn2) {
					// start 2 turns
					if (angle2pos > 0) {
						// this.debugMovesOut("turn: 180");
						TurnAction t1 = new TurnAction(180);
						return t1;
					}
          // this.debugMovesOut("turn: -180");
          TurnAction t1 = new TurnAction(-180);
          return t1;
				} else if (abs(angle2pos) <= turn3) {
					// start 3 turns
					if (angle2pos > 0) {
						TurnAction t1 = new TurnAction(180);
						return t1;
					}
          TurnAction t1 = new TurnAction(-180);
          return t1;
				} else {
					// start 4 turns
					if (angle2pos > 0) {
						TurnAction t1 = new TurnAction(180);
						return t1;
					}
          TurnAction t1 = new TurnAction(-180);
          return t1;
          // end 4 turns
				}
				// begin dashes
				boolean reached = false;
				if (dummyPlayer.getPosition().getDistance(pos) < reachedDist) {
					reached = true;
				}
				double actspeed = 0;
				double decay = dummyPlayer.getPConf().PLAYER_DECAY;
				double dpr = dummyPlayer.getPConf().DASH_POWER_RATE;
				double decaydist = 0;
				double actdist = 0;
				while (!reached) {
					actspeed = dummyPlayer.getSpeed().getLength();
					decaydist = actspeed + (decay * actspeed)
							+ (decay * decay * actspeed);
					actdist = dummyPlayer.getDistance(pos);
					if (actdist > decaydist + reachedDist) {
						DashAction d = new DashAction(100);
						return d;
					}
          int dashpower = (int) round((actdist - decaydist)
          		/ ((1 + decay + decay * decay) * dpr));
          dashpower = max(-100, min(100, dashpower));
          // this.debugMovesOut("dash: "+dashpower);
          DashAction d = new DashAction(dashpower);
          return d;
				}
				// end forward
			} else {
				// begin backward
				angle2pos = normalize(angle2pos + 180);
				if (abs(angle2pos) <= turn1) {
					// start 1 turn
					if (abs(angle2pos) > turnBuffer) {
						// this.debugMovesOut("turn: "+getTurnArg(angle2pos,
						// p));
						TurnAction t1 = new TurnAction(getTurnArg(angle2pos, p));
						return t1;
					}
					// end 1 turn
				} else if (abs(angle2pos) <= turn2) {
					// start 2 turns
					if (angle2pos > 0) {
						TurnAction t1 = new TurnAction(180);
						return t1;
					}
          TurnAction t1 = new TurnAction(-180);
          return t1;
				} else if (abs(angle2pos) <= turn3) {
					// start 3 turns
					if (angle2pos > 0) {
						TurnAction t1 = new TurnAction(180);
						return t1;
					}
          TurnAction t1 = new TurnAction(-180);
          return t1;
				} else {
					// start 4 turns
					if (angle2pos > 0) {
						TurnAction t1 = new TurnAction(180);
						return t1;
					}
          TurnAction t1 = new TurnAction(-180);
          return t1;
				}
				// begin dashes
				boolean reached = false;
				if (dummyPlayer.getPosition().getDistance(pos) < reachedDist) {
					reached = true;
				}
				double actspeed = 0;
				double decay = dummyPlayer.getPConf().PLAYER_DECAY;
				double dpr = dummyPlayer.getPConf().DASH_POWER_RATE;
				double decaydist = 0;
				double actdist = 0;
				while (!reached) {
					actspeed = dummyPlayer.getSpeed().getLength();
					decaydist = actspeed + (decay * actspeed)
							+ (decay * decay * actspeed);
					actdist = dummyPlayer.getDistance(pos);
					if (actdist > decaydist + reachedDist) {
						// this.debugMovesOut("big dist");
						DashAction d = new DashAction(-100);
						return d;
					}
          // this.debugMovesOut("last dash");
          int dashpower = -(int) round((actdist - decaydist)
          		/ ((1 + decay + decay * decay) * dpr));
          dashpower = max(-100, min(100, dashpower));
          // this.debugMovesOut("dash: "+dashpower);
          DashAction d = new DashAction(dashpower);
          return d;
				}
				// end backward
			}
			// end not in reached dist
		}
		// this.debugMovesOut("turn to desired pos");
		// turn to desired pos
		if (turnToPos != null) {
			angle2pos = normalize(dummyPlayer.getAngleTo(turnToPos) - bodyDir);
			if (abs(angle2pos) <= turn1) {
				// start 1 turn
				if (abs(angle2pos) > turnBuffer) {
					// this.debugMovesOut("turn: "+getTurnArg(angle2pos, p));
					TurnAction t1 = new TurnAction(getTurnArg(angle2pos, p));
					return t1;
				}
				// end 1 turn
			} else if (abs(angle2pos) <= turn2) {
				// start 2 turns
				if (angle2pos > 0) {
					// this.debugMovesOut("turn: 180");
					TurnAction t1 = new TurnAction(180);
					return t1;
				}
        // this.debugMovesOut("turn: -180");
        TurnAction t1 = new TurnAction(-180);
        return t1;
			} else if (abs(angle2pos) <= turn3) {
				// start 3 turns
				if (angle2pos > 0) {
					// this.debugMovesOut("turn: 180");
					TurnAction t1 = new TurnAction(180);
					return t1;
				}
        // this.debugMovesOut("turn: -180");
        TurnAction t1 = new TurnAction(-180);
        return t1;
			} else {
				// start 4 turns
				if (angle2pos > 0) {
					// this.debugMovesOut("turn: 180");
					TurnAction t1 = new TurnAction(180);
					return t1;
				}
        // this.debugMovesOut("turn: -180");
        TurnAction t1 = new TurnAction(-180);
        return t1;
			}
		}
		TurnAction t = new TurnAction(0);
		// this.debugMovesOut("no action, add turn 0");
		return t;
	}

	/**
	 * 
	 * @param pos
	 *            the position to reach a list of movements to reach the given
	 *            position as fast as possible under the given conditions
	 * @return the list of actions to reach a point
	 */
	public LinkedList<Action> getMovesToPos(Vektor pos) {
		return getMovesToPos(pos, 1, 3, false, -1, null, null);
	}

	/**
	 * 
	 * @param pos
	 *            the position to reach
	 * @param backwards
	 *            if this is true, then the player checks if it is faster to
	 *            come backwards to the desired position otherwise the player
	 *            runs definitely forward
	 * @param watchPos
	 *            gives a position that should be watchable during all movements
	 *            and influences in this way the decision to move backward or
	 *            not.
	 * 
	 * sometimes the position is watchable only for a few cycles during the move
	 * in this case the pos is watchable during the first moves of the list
	 * 
	 * if it is null, it will be ignored if "backwards" is false, watchPos will
	 * be ignored
	 * @param turnToPos
	 *            after all movements are done, the player will turn his body to
	 *            this position if null, no turn will be performed after the
	 *            normal moves
	 * @return a list of movements to reach the given position as fast as
	 *         possible under the given conditions
	 */
	public LinkedList<Action> getMovesToPos(Vektor pos, boolean backwards,
			Vektor watchPos, Vektor turnToPos) {
		return getMovesToPos(pos, 1, 3, backwards, -1, watchPos, turnToPos);
	}

	/**
	 * 
	 * @param pos
	 *            the position to reach
	 * @param backwards
	 *            if this is true, then the player checks if it is faster to
	 *            come backwards to the desired position otherwise the player
	 *            runs definitely forward
	 * @param turnToPos
	 *            after all movements are done, the player will turn his body to
	 *            this position if null, no turn will be performed after the
	 *            normal moves
	 * @return a list of movements to reach the given position as fast as
	 *         possible under the given conditions
	 */
	public LinkedList<Action> getMovesToPos(Vektor pos, boolean backwards,
			Vektor turnToPos) {
		return getMovesToPos(pos, 1, 3, backwards, -1, null, turnToPos);
	}

	/**
	 * @param l the line to intersect
	 * @return the intersetctionpoint with the reachableArea of the placer an the line
	 */
	public LinkedList<Vektor> getIntersectionPointsWithLine(Line l) {
		LinkedList<Vektor> list = new LinkedList<Vektor>();
		double ballSize = SConf.getInstance().BALL_SIZE;
		dummyLine.setPoint1(pos);
		dummyLine.setPoint2(pos.add(new Vektor(dash0, bodyDir)));
		Vektor iPos = dummyLine.getIntersectionPointWithLine(l);
		if (pos.getDistance(iPos) > dash1 - ballSize
				&& pos.getDistance(iPos) <= dash0 - ballSize
				&& abs(normalize(pos.getAngleTo(iPos) - bodyDir)) < 90) {
			list.add(iPos.cloned());
		}
		dummyCircle.setCenter(pos);
		dummyCircle.setRadius(dash1 - ballSize);
		LinkedList<Vektor> positions = dummyCircle.getIntersectionPoints(l);
		for (Vektor po : positions) {
			if (abs(normalize(pos.getAngleTo(po) - bodyDir)) < turn1 - 1) {
				list.add(po.cloned());
			}
		}
		dummyLine.setPoint2(pos.add(new Vektor(dash1, normalize(turn1 - 1
				- bodyDir))));
		iPos = dummyLine.getIntersectionPointWithLine(l);
		if (pos.getDistance(iPos) > dash2 - ballSize
				&& pos.getDistance(iPos) <= dash1 - ballSize
				&& abs(abs(pos.getAngleTo(iPos) - bodyDir) - turn1) < 5) {
			list.add(iPos.cloned());
		}
		dummyLine.setPoint2(pos.add(new Vektor(dash1, normalize(-(turn1 - 1)
				- bodyDir))));
		iPos = dummyLine.getIntersectionPointWithLine(l);
		if (pos.getDistance(iPos) > dash2 - ballSize
				&& pos.getDistance(iPos) <= dash1 - ballSize
				&& abs(abs(pos.getAngleTo(iPos) - bodyDir) - turn1) < 5) {
			list.add(iPos.cloned());
		}
		dummyCircle.setRadius(dash2 - ballSize);
		positions = dummyCircle.getIntersectionPoints(l);
		for (Vektor po : positions) {
			if (abs(normalize(pos.getAngleTo(po) - bodyDir)) < turn2 - 1
					&& abs(normalize(pos.getAngleTo(po) - bodyDir)) >= turn1 - 1) {
				list.add(po.cloned());
			}
		}
		dummyLine.setPoint2(pos.add(new Vektor(dash2, normalize(turn2 - 1
				- bodyDir))));
		iPos = dummyLine.getIntersectionPointWithLine(l);
		if (pos.getDistance(iPos) > dash3 - ballSize
				&& pos.getDistance(iPos) <= dash2 - ballSize
				&& abs(abs(pos.getAngleTo(iPos) - bodyDir) - turn2) < 5) {
			list.add(iPos.cloned());
		}
		dummyLine.setPoint2(pos.add(new Vektor(dash2, normalize(-(turn2 - 1)
				- bodyDir))));
		iPos = dummyLine.getIntersectionPointWithLine(l);
		if (pos.getDistance(iPos) > dash3 - ballSize
				&& pos.getDistance(iPos) <= dash2 - ballSize
				&& abs(abs(pos.getAngleTo(iPos) - bodyDir) - turn2) < 5) {
			list.add(iPos.cloned());
		}
		dummyCircle.setRadius(dash3 - ballSize);
		positions = dummyCircle.getIntersectionPoints(l);
		for (Vektor po : positions) {
			if (abs(normalize(pos.getAngleTo(po) - bodyDir)) < turn3 - 1
					&& abs(normalize(pos.getAngleTo(po) - bodyDir)) >= turn2 - 1) {
				list.add(po.cloned());
			}
		}
		dummyLine.setPoint2(pos.add(new Vektor(dash3, normalize(turn3 - 1
				- bodyDir))));
		iPos = dummyLine.getIntersectionPointWithLine(l);
		if (pos.getDistance(iPos) > dash4 - ballSize
				&& pos.getDistance(iPos) <= dash3 - ballSize
				&& abs(abs(pos.getAngleTo(iPos) - bodyDir) - turn3) < 5) {
			list.add(iPos.cloned());
		}
		dummyLine.setPoint2(pos.add(new Vektor(dash3, normalize(-(turn3 - 1)
				- bodyDir))));
		iPos = dummyLine.getIntersectionPointWithLine(l);
		if (pos.getDistance(iPos) > dash4 - ballSize
				&& pos.getDistance(iPos) <= dash3 - ballSize
				&& abs(abs(pos.getAngleTo(iPos) - bodyDir) - turn3) < 5) {
			list.add(iPos.cloned());
		}
		dummyCircle.setRadius(dash4 - ballSize);
		positions = dummyCircle.getIntersectionPoints(l);
		for (Vektor po : positions) {
			if (abs(normalize(pos.getAngleTo(po) - bodyDir)) >= turn3 - 1) {
				list.add(po.cloned());
			}
		}
		return list;
	}
}
